package com.papper.mng.filter;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Sets;
import com.papper.common.bean.sys.SysLimit;
import com.papper.common.bean.sys.SysResource;
import com.papper.common.bean.sys.SysSystem;
import com.papper.common.bean.sys.SysUser;
import com.papper.common.config.LoginConfig;
import com.papper.common.config.SysSystemHelp;
import com.papper.common.constant.SystemConstants;
import com.papper.common.service.sys.SysLimitService;
import com.papper.common.service.sys.SysResourceService;
import com.papper.common.utils.PapperSpringUtil;
import com.papper.mng.controller.WebContext;
import com.papper.mng.domain.DwzResponse;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.AntPathMatcher;
import tk.mybatis.mapper.util.StringUtil;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URLEncoder;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

/**
 * @Author:Lajiao
 * @Date:2014年8月22日
 * @Time:上午9:19:57
 * @Description:请求过滤条件
 */
public class RequestFilter implements Filter {
    private final static Logger      logger        = LoggerFactory.getLogger(RequestFilter.class);
    /**
     * 过滤-不检验
     */
    private              Set<String> exclude       = Sets.newHashSet();
    /**
     * 过滤-渠道允许访问路径
     */
    private              Set<String> sourceinclude = Sets.newHashSet();

    private final static String LOGIN_PATH = "/login";
    private final static String LIMIT_PATH = "/limit";

    @Override
    public void init(FilterConfig config) throws ServletException {
        try {
            // 加载配置文件
            InputStream fis = Thread.currentThread().getContextClassLoader().getResourceAsStream("filter.xml");
            if (fis == null) {
                logger.error("系统过滤配置文件[{}]为空!!!!!!", "filter.xml");
                return;
            }
            InputStreamReader isr = new InputStreamReader(fis, "utf-8");
            if (isr == null) {
                logger.error("系统过滤配置文件[{}]为空!!!!!!", "filter.xml");
                return;
            }
            SAXReader reader   = new SAXReader();
            Document  document = reader.read(isr);
            List      nodes    = document.getRootElement().elements("props");
            for (Iterator it = nodes.iterator(); it.hasNext(); ) {
                Element elm = (Element) it.next();
                if (elm.attributeValue("name").equals("exclude")) {
                    List props = elm.elements("prop");
                    for (Iterator pit = props.iterator(); pit.hasNext(); ) {
                        Element pelm = (Element) pit.next();
                        exclude.add(pelm.attributeValue("url"));
                    }
                }
                if (elm.attributeValue("name").equals("login")) {
                    List props = elm.elements("prop");
                    for (Iterator pit = props.iterator(); pit.hasNext(); ) {
                        Element pelm = (Element) pit.next();
                        sourceinclude.add(pelm.attributeValue("url"));
                    }
                }
            }
            isr.close();
            fis.close();
        } catch (Exception e) {
            logger.error("系统过滤配置导入异常:[{}]", e.getMessage());
            return;
        }
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest  request  = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        HttpSession         session  = request.getSession();
        String              strUrl   = request.getServletPath();

        WebContext.setServletRequest(request);
        WebContext.setServletResponse(response);
        WebContext.setHttpSession(request.getSession());

        ServletContext application   = request.getSession().getServletContext();
        String         systemCdnPath = SysSystemHelp.I().config("systemCdnPath");
        if (StringUtil.isEmpty(systemCdnPath)) {
            application.setAttribute("systemCdnPath", "");
        } else {
            application.setAttribute("systemCdnPath", systemCdnPath);
        }
        /**
         * 超级用户校验
         */
        SysUser sysUser = (SysUser) session.getAttribute(SystemConstants.SESSION.SESSION_ADMIN_LOGIN);
        if (sysUser != null && sysUser.getId().intValue() == 0) {
            String cacheValue = LoginConfig.I().getSession(sysUser.getId().toString());
            if (cacheValue != null && !cacheValue.equals(session.getId())) {
                WebContext.getHttpSession().removeAttribute(SystemConstants.SESSION.SESSION_ADMIN_LOGIN);
                // 登录已失效
                String       strContextPath = request.getContextPath();
                StringBuffer strRedirect    = new StringBuffer();
                strRedirect.append("/").append(strContextPath);
                strRedirect.append("/").append(LOGIN_PATH);
                strRedirect.append("?callBack=").append(URLEncoder.encode(strUrl, "UTF-8"));
                strRedirect.append("&error=").append(URLEncoder.encode("您在其它地方已登录,请确认是否本人登录", "UTF-8"));
                response.sendRedirect(strRedirect.toString().replaceAll("[/]+", "/"));
                return;
            } else if (cacheValue == null) {
                LoginConfig.I().putSession(sysUser.getId().toString(), session.getId());
            }
            chain.doFilter(servletRequest, servletResponse);
            return;
        }
        /**
         * 过滤外请求
         */
        if (isInclude(strUrl, exclude)) {
            chain.doFilter(servletRequest, servletResponse);
            return;
        }
        /**
         * 普通用户未登录
         */
        if (sysUser == null) {
            if (strUrl.endsWith("htm")) {
                String       strContextPath = request.getContextPath();
                StringBuffer strRedirect    = new StringBuffer();
                strRedirect.append("/").append(strContextPath);
                strRedirect.append("/").append(LOGIN_PATH);
                strRedirect.append("?callBack=").append(URLEncoder.encode(strUrl, "UTF-8"));
                response.sendRedirect(strRedirect.toString().replaceAll("[/]+", "/"));
                return;
            } else if (strUrl.endsWith("jsonp")) {
                response.setContentType("application/json;charset=utf-8");
                response.setCharacterEncoding("utf-8");
                response.getWriter().write(JSON.toJSONString(new DwzResponse("403", "您尚未登录,暂无法请求该数据!!!")));
                response.flushBuffer();
                return;
            } else {
                String       strContextPath = request.getContextPath();
                StringBuffer strRedirect    = new StringBuffer();
                strRedirect.append("/").append(strContextPath);
                strRedirect.append("/").append(LOGIN_PATH);
                strRedirect.append("?callBack=").append(URLEncoder.encode(strUrl, "UTF-8"));
                response.sendRedirect(strRedirect.toString().replaceAll("[/]+", "/"));
                return;
            }
        }
        /**
         * 普通已登录
         */
        if (isInclude(strUrl, sourceinclude)) {
            chain.doFilter(servletRequest, servletResponse);
            return;
        }
        // 普通用户已登录
        SysLimit sysLimit = match(strUrl, sysUser);
        if (sysLimit == null) {
            String strContextPath = request.getContextPath();
            String strRedirect    = "/" + strContextPath + "/" + LIMIT_PATH;
            strRedirect = strRedirect.replaceAll("[/]+", "/");
            response.sendRedirect(strRedirect);
            return;
        }
        String cacheValue = LoginConfig.I().getSession(sysUser.getId().toString());
        if (cacheValue != null && !cacheValue.equals(session.getId())) {
            // 登录已失效
            WebContext.getHttpSession().removeAttribute(SystemConstants.SESSION.SESSION_ADMIN_LOGIN);
            String       strContextPath = request.getContextPath();
            StringBuffer strRedirect    = new StringBuffer();
            strRedirect.append("/").append(strContextPath);
            strRedirect.append("/").append(LOGIN_PATH);
            strRedirect.append("?callBack=").append(URLEncoder.encode(strUrl, "UTF-8"));
            strRedirect.append("&error=").append(URLEncoder.encode("您在其它地方已登录,请确认是否本人登录", "UTF-8"));
            response.sendRedirect(strRedirect.toString().replaceAll("[/]+", "/"));
            return;
        } else if (cacheValue == null) {
            LoginConfig.I().putSession(sysUser.getId().toString(), session.getId());
        }
        chain.doFilter(servletRequest, servletResponse);
        return;
    }

    @Override
    public void destroy() {
        return;
    }

    /**
     * 是否包含
     *
     * @param url
     * @return
     */
    public boolean isInclude(String url, Set<String> comp) {
        if (url != null) {
            AntPathMatcher path = new AntPathMatcher();
            for (String str : comp) {
                if (path.match(str, url)) {
                    return true;
                }
            }
            return false;
        }
        return false;
    }

    /**
     * 权限匹配
     *
     * @param url     the url
     * @param sysUser the sys user
     * @return the sys limit
     */
    public SysLimit match(String url, SysUser sysUser) {
        if (url == null || StringUtil.isEmpty(url)) {
            return null;
        }
        SysSystem          sysSystem   = SysSystemHelp.I().sys();
        SysResourceService s           = (SysResourceService) PapperSpringUtil.getBean("sysResourceService");
        List<SysResource>  allResource = s.findAll();
        if (allResource == null || allResource.isEmpty()) {
            return null;
        }
        String compareUrl;
        for (SysResource sr : allResource) {
            compareUrl = "/" + sr.getResUrl();
            if (url.equals(compareUrl) && sr.getSystemId().intValue() == sysSystem.getId().intValue()) {
                SysLimitService sl = (SysLimitService) PapperSpringUtil.getBean("sysLimitService");
                return sl.getUserLimit(sysUser.getLimitType(), sysUser.getId(), sysUser.getGroupId(), sr.getId());
            }
        }
        return null;
    }
}
